﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Data;

namespace SyncTool
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        SyncPlan currentPlan = new SyncPlan();
        bool isShutdownPlan = false;
        private NotifyIcon notifyIcon = null;

        List<string> excludeKeywords = new List<string>();

        #region property
        public string Source
        {
            get { return (string)GetValue(SourceProperty); }
            set { SetValue(SourceProperty, value); }
        }
        public static DependencyProperty SourceProperty = DependencyProperty.Register("Source", typeof(string), typeof(MainWindow));

        public string Destination
        {
            get { return (string)GetValue(DestinationProperty); }
            set { SetValue(DestinationProperty, value); }
        }
        public static DependencyProperty DestinationProperty = DependencyProperty.Register("Destination", typeof(string), typeof(MainWindow));

        public bool IsEdit
        {
            get { return (bool)GetValue(IsEditProperty); }
            set { SetValue(IsEditProperty, value); }
        }
        public static DependencyProperty IsEditProperty = DependencyProperty.Register("IsEdit", typeof(bool), typeof(MainWindow), new PropertyMetadata(true));
        #endregion

        #region constructor
        public MainWindow()
        {
            InitializeComponent();
            initNotifyIcon();
            var name = DateTime.Now.ToString("yyyyMMdd_HHmmss");
            LogHelper.Init(name);
            Loaded += new RoutedEventHandler(MainWindow_Loaded);
            Closed += new EventHandler(MainWindow_Closed);
            chkShutdown.Click += new RoutedEventHandler(chkShutdown_Click);
            this.StateChanged += new EventHandler(MainWindow_StateChanged);
        }

        void MainWindow_StateChanged(object sender, EventArgs e)
        {
            if (this.WindowState == System.Windows.WindowState.Minimized)
                this.Visibility = System.Windows.Visibility.Hidden;
        }

        void initNotifyIcon()
        {
            //设置托盘的各个属性
            notifyIcon = new NotifyIcon();
            //notifyIcon.BalloonTipText = "sync runnning...";
            notifyIcon.Text = "sync";
            notifyIcon.Icon = SyncTool.Properties.Resources.sync;
            notifyIcon.Visible = true;
            //notifyIcon.ShowBalloonTip(2000);
            notifyIcon.MouseClick += new MouseEventHandler(notifyIcon_MouseClick);

            MenuItem show = new MenuItem("show");
            show.Click += new EventHandler(show_Click);

            MenuItem exit = new MenuItem("exit");
            exit.Click += new EventHandler(exit_Click);


            MenuItem[] childen = new MenuItem[] { show, exit };
            notifyIcon.ContextMenu = new ContextMenu(childen);

        }

        void show_Click(object sender, EventArgs e)
        {
            this.Visibility = System.Windows.Visibility.Visible;
            this.WindowState = System.Windows.WindowState.Normal;
            this.Activate();
        }

        void exit_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        void notifyIcon_MouseClick(object sender, MouseEventArgs e)
        {
            this.Visibility = System.Windows.Visibility.Visible;
            this.WindowState = System.Windows.WindowState.Normal;
            this.Activate();
        }

        void chkShutdown_Click(object sender, RoutedEventArgs e)
        {
            isShutdownPlan = chkShutdown.IsChecked.Value;
            if (!isShutdownPlan)
                cancelShutdown();
        }
        #endregion

        #region event handle
        private void btnDestination_Click(object sender, RoutedEventArgs e)
        {
            FolderBrowserDialog dialog = new FolderBrowserDialog();
            dialog.ShowNewFolderButton = true;
            dialog.Description = "Please chose a destination folder";
            dialog.RootFolder = Environment.SpecialFolder.MyComputer;
            dialog.ShowDialog();
            Destination = dialog.SelectedPath;
            currentPlan.Desination = Destination;
        }

        private void btnSource_Click(object sender, RoutedEventArgs e)
        {
            FolderBrowserDialog dialog = new FolderBrowserDialog();
            dialog.ShowNewFolderButton = false;
            dialog.Description = "Please chose a source folder";
            dialog.RootFolder = Environment.SpecialFolder.MyComputer;
            dialog.ShowDialog();
            Source = dialog.SelectedPath;
            currentPlan.Source = Source;
        }

        private void btnCancel_Click(object sender, RoutedEventArgs e)
        {
            cancelSource.Cancel();
            IsEdit = true;
        }

        private void btnGo_Click(object sender, RoutedEventArgs e)
        {
            IsEdit = false;
            Scan();
        }

        void MainWindow_Closed(object sender, EventArgs e)
        {
            if (currentPlan != null)
                SyncPlanHelper.Save(currentPlan);
        }

        void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            var plan = SyncPlanHelper.Read();
            if (plan != null)
            {
                currentPlan = plan;
                Source = currentPlan.Source;
                Destination = currentPlan.Desination;
            }

            excludeKeywords.Add("$RECYCLE.BIN");
            excludeKeywords.Add("System Volume Information");
            excludeKeywords.Add("bootsqm.dat");
        }
        #endregion

        #region family method
        List<string> filesList = new List<string>();

        CancellationTokenSource cancelSource = new CancellationTokenSource();

        string _source, _destination;
        void Scan()
        {
            Invoke(
               delegate
               {
                   _source = Source;
                   _destination = Destination;
                   tb.Text = "Start...";
                   IsEdit = true;
               });
            cancelSource = new CancellationTokenSource();
            filesList.Clear();
            var newTask = Task.Factory.StartNew(CollectPathAction(), _source, cancelSource.Token);
            newTask.ContinueWith((ex) =>
            {
                Invoke(
                delegate
                {
                    tb.Text = "Finished";
                    IsEdit = true;
                    if (isShutdownPlan)
                        shutdown();
                });
            });
        }

        void WriteException(Exception ex)
        {
            LogHelper.WriteException(ex, " ");
        }

        void CollectFile(object path)
        {
            string currentPath = path as string;
            if (string.IsNullOrEmpty(currentPath)) return;

            IEnumerable<string> files = null, folders = null;

            #region files
            try
            {
                files = Directory.EnumerateFiles(currentPath);
            }
            catch (Exception ex)
            {
                LogHelper.WriteException(ex, "EnumerateFiles:" + currentPath);
            }
            if (files != null)
            {
                foreach (var file in files)
                {
                    if (cancelSource.IsCancellationRequested) break;

                    if (excludeKeywords.Any(o => file.ToUpper().Contains(o.ToUpper())))
                        continue;

                    try
                    {
                        string relativePath = file.Replace(_source, "");
                        if (!_destination.EndsWith(@"\"))
                            _destination += @"\";
                        string aimPath = _destination + relativePath;
                        if (!File.Exists(aimPath))
                            File.Copy(file, aimPath);
                        else
                        {
                            DateTime sourceTime = File.GetLastWriteTime(file);
                            DateTime aimTime = File.GetLastWriteTime(aimPath);

                            if (aimTime < sourceTime)
                            {
                                File.Copy(file, aimPath, true);
                                File.SetLastWriteTime(aimPath, sourceTime);
                            }
                        }
                        Invoke(delegate
                        {
                            tb.Text = file;
                        });
                        LogHelper.Write("File: {0}-->OK ", file);
                    }
                    catch (Exception ex)
                    {
                        LogHelper.Write("File: {0}-->Fail", file);
                        //throw ex;
                    }
                }
            }
            #endregion

            #region folders
            try
            {
                folders = Directory.EnumerateDirectories(currentPath);
            }
            catch (Exception ex)
            {
                LogHelper.WriteException(ex, "EnumerateDirectories:" + currentPath);
            }
            if (folders != null)
            {
                foreach (var folder in folders)
                {
                    if (cancelSource.IsCancellationRequested) break;
                    if (excludeKeywords.Any(o => folder.ToUpper().Contains(o.ToUpper())))
                        continue;

                    try
                    {
                        string relativePath = folder.Replace(_source, "");

                        if (!_destination.EndsWith(@"\"))
                            _destination += @"\";
                        string aimPath = _destination + relativePath;

                        if (!Directory.Exists(aimPath))
                        {
                            Directory.CreateDirectory(aimPath);
                        }
                        LogHelper.Write("Folder: {0}-->OK", folder);
                    }
                    catch (Exception ex)
                    {
                        LogHelper.Write("Folder: {0}-->Fail", folder);
                        // throw ex;
                    }
                    Invoke(delegate
                    {
                        tb.Text = folder;
                    });

                    CollectFile(folder);
                    //var newTask = Task.Factory.StartNew(CollectPathAction(), folder, cancelSource.Token);
                    //newTask.ContinueWith(ex => WriteException(ex.Exception), System.Threading.Tasks.TaskContinuationOptions.OnlyOnFaulted);
                }
            }
            #endregion
        }

        void Invoke(Action a)
        {
            this.Dispatcher.Invoke(a);
        }

        Action<object> CollectPathAction()
        { return new Action<object>(filePath => { CollectFile(filePath); }); }
        #endregion


        void shutdown()
        {
            var root = AppDomain.CurrentDomain.BaseDirectory.Substring(0, 2);

            Process p = new Process();
            p.StartInfo.FileName = "cmd.exe";
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.RedirectStandardInput = true;
            p.StartInfo.CreateNoWindow = true;
            p.Start();
            p.StandardInput.WriteLine(root);
            p.StandardInput.WriteLine("shutdown -s -t 600");
            p.Close();
        }

        void cancelShutdown()
        {
            var root = AppDomain.CurrentDomain.BaseDirectory.Substring(0, 2);

            Process p = new Process();
            p.StartInfo.FileName = "cmd.exe";
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.RedirectStandardInput = true;
            p.StartInfo.CreateNoWindow = true;
            p.Start();
            p.StandardInput.WriteLine(root);
            p.StandardInput.WriteLine("shutdown -a");
            p.Close();
        }
    }

    public class BoolConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value == null) return false;
            if (value.ToString() == Boolean.TrueString) return false;
            return true;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

}
